package com.piesat.quake.business.device.mqtt.factory;

import com.piesat.quake.business.device.mqtt.anno.NodeField;
import com.piesat.quake.business.device.mqtt.anno.PipelineNode;
import com.piesat.quake.business.device.mqtt.pipeline.Pipeline;
import com.piesat.quake.business.device.mqtt.pipeline.datahandler.DataHandler;

import java.lang.reflect.Field;

/**
 * 通过注解创建流水的厂类
 *
 * @author Gersy
 * @date 2023/3/8
 * @since 1.0
 */
public class AnnotationPipelineFactory implements PipelineFactory<Class<?>> {
    public Pipeline create(Class<?> clazz) {
        PipelineNode annotation = clazz.getAnnotation(PipelineNode.class);
        if (annotation == null) {
            throw new IllegalStateException("没有找到@PipelineNode注解：" + clazz.getName());
        }
        Class<?>[] preNodes = annotation.preNodes();
        Pipeline pipeline = new Pipeline(clazz);
        for (Class<?> preNode : preNodes) {
            add(pipeline, preNode);
        }
        add(pipeline, clazz);
        return pipeline;
    }

    private void add(Pipeline pipeline, Class<?> aClass) {
        pipeline.addLast(aClass);
        handleNode(pipeline, aClass, pipeline.getLast());
    }

    private void handleNode(Pipeline pipeline, Class<?> aClass, DataHandler dataHandler) {
        Field[] fields = aClass.getDeclaredFields();
        for (Field field : fields) {
            NodeField fieldAnnotation = field.getAnnotation(NodeField.class);
            if (fieldAnnotation != null) {
                String name = fieldAnnotation.name();
                Class<?> clazz = fieldAnnotation.clazz();
                Class<?> type = clazz == Object.class ? field.getType() : clazz;
                String nodeFieldName = dataHandler.getNodeFieldName();
                if (nodeFieldName == null) {
                    pipeline.addNode(type, name.length() > 0 ? name : field.getName(),fieldAnnotation.excludeFields());
                } else {
                    pipeline.addNode(type, nodeFieldName, name.length() > 0 ? name : field.getName(), fieldAnnotation.size());
                }
                handleNode(pipeline, type, pipeline.getLast());
            }
        }
    }
}
